// Copyright 2012 Google Inc. All Rights Reserved.

/**
 * @fileoverview Implements the Google Hangouts Effects app.
 *   Requires that jquery and googui jquery plugin have been loaded.
 * @author jbaer@google.com (Jeremy Baer)
 */

// structures to handle overlays
var gOverlays = [];
var gOverlayData = [];
var gOverlayToCategoryMap = [];
var gCurrentOverlays = [];
var gOverlayTimestamps = [];
var gOverlayRoot = gResourceRoot;

var gParticipants = [];

var gStrings = [];

/**
 * Given a string tag, returns the string for that tag in the current 
 * language. 
 * @param {string} tag The tag name
 * @return {string} The localized string 
 */
function getLocalizedString(tag)
{
  if(gStrings && tag in gStrings)
    return gStrings[tag];
  else return tag;
}


/**
 * Creates a data structure containing info for all the overlay
 * effects and their buttons. Also creates the overlays themselves.
 */
function createOverlays()
{
  gOverlayData = [ {
    id: 'special',
    title: getLocalizedString('Late_Night_Hosts'),
    overlays: [ 
      {
        name: getLocalizedString('Conan_Hair'),
        id: 'cob-hair',
        icon: gResourceRoot + 'fx/overlays/COB_Hair-icon.png',
        resource: gOverlayRoot +'fx/overlays/COB_Hair.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.0, y: -0.50},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.73}
      }
    ]
  },
  {
    id: 'headwear',
    title: getLocalizedString('Headwear'),
    overlays: [ 
      {
        name: getLocalizedString('Cat_Hat'),
        id: 'cat-hat',
        icon: gResourceRoot + 'fx/overlays/Dr.Seuss_hat-icon.png',
        resource: gOverlayRoot +'fx/overlays/Dr.Seuss_hat.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.0, y: -0.7},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.7}
      },
      {
        name: getLocalizedString('Crown'),
        id: 'crown',
        icon: gResourceRoot + 'fx/overlays/Crown-icon.png',
        resource: gOverlayRoot +'fx/overlays/Crown.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.0, y: -0.9},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.65}
       },
       {
         name: getLocalizedString('Tiara'),
         id: 'tiara',
         icon: gResourceRoot + 'fx/overlays/Tiara-icon.png',
         resource: gOverlayRoot +'fx/overlays/Tiara.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                     offset: {x: 0.0, y: -0.9},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.65}
       },
       {
         name: getLocalizedString('Pirate_Hat'),
         id: 'pirate-hat',
         icon: gResourceRoot + 'fx/overlays/PirateHat-icon.png',
         resource: gOverlayRoot +'fx/overlays/PirateHat.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.2},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.8}
       },
       {
         name: getLocalizedString('Clown_Head'),
         id: 'clown-head',
         icon: gResourceRoot + 'fx/overlays/Clownhead-icon.png',
         resource: gOverlayRoot +'fx/overlays/Clownhead.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.55},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.8}
       },
       {
         name: getLocalizedString('Sweatband'),
         id: 'sweatband',
         icon: gResourceRoot + 'fx/overlays/Sweatband-icon.png',
         resource: gOverlayRoot +'fx/overlays/Sweatband.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.52},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.7}
       },
       {
         name: getLocalizedString('Top_Hat'),
         id: 'top-hat',
         icon: gResourceRoot + 'fx/overlays/hat-icon.png',
         resource: gOverlayRoot + 'fx/overlays/topHat.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: -0.02, y: -0.90},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.9}
       },
       {
         name: getLocalizedString('Birthday_Hat'),
         id: 'birthday-hat',
         icon: gResourceRoot + 'fx/overlays/Birthday_hat-icon.png',
         resource: gOverlayRoot + 'fx/overlays/Birthday_hat.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: -0.02, y: -0.50},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.85}
       },
       {
         name: getLocalizedString('Halo'),
         id: 'halo',
         icon: gResourceRoot + 'fx/overlays/halo-icon.png',
         resource: gOverlayRoot + 'fx/overlays/halo.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.82},
                    scaleWithFace: true,
                    rotateWithFace: true}
       },
       {
         name: getLocalizedString('Horns'),
         id: 'horns',
         icon: gResourceRoot + 'fx/overlays/horns-icon.png',
         resource: gOverlayRoot + 'fx/overlays/horns.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.65},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.7}
       },
       {
         name: getLocalizedString('Hearts'),
         id: 'hearts',
         icon: gResourceRoot + 'fx/overlays/Hearts-icon.png',
         resource: gOverlayRoot + 'fx/overlays/Hearts.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -1.05},
                    scaleWithFace: true,
                    rotateWithFace: true}
       },
       {
         name: getLocalizedString('Confused'),
         id: 'confused',
         icon: gResourceRoot + 'fx/overlays/Confused-icon.png',
         resource: gOverlayRoot + 'fx/overlays/Confused.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.6},
                    scaleWithFace: true,
                    rotateWithFace: true}
       },
       {
         name: getLocalizedString('Mohawk'),
         id: 'mohawk',
         icon: gResourceRoot + 'fx/overlays/Mohawk-icon.png',
         resource: gOverlayRoot + 'fx/overlays/Mohawk.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -1.0},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.7}
       },
       {
         name: getLocalizedString('Dog'),
         id: 'dog',
         icon: gResourceRoot + 'fx/overlays/dog-icon.png',
         resource: gOverlayRoot +'fx/overlays/dog.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: 0.04},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.7}
       },
       {
         name: getLocalizedString('Cat'),
         id: 'cat',
         icon: gResourceRoot + 'fx/overlays/cat-icon.png',
         resource: gOverlayRoot +'fx/overlays/cat.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: -0.35},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 0.7}
       },
       {
         name: getLocalizedString('Astronaut_Helmet'),
         id: 'astronaut-helmet',
         icon: gResourceRoot + 'fx/overlays/StartExploring_overlay-icon.png',
         resource: gOverlayRoot +'fx/overlays/StartExploring_overlay.png',
         options:  {trackingFeature:
                    gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                    offset: {x: 0.0, y: 0.1},
                    scaleWithFace: true,
                    rotateWithFace: true,
                    scale: 1.1}
       }
     ]
  },
  {
    id: 'eyewear',
    title: getLocalizedString('Eyewear'),
    overlays: [ 
    {
        name: getLocalizedString('Sunglasses'),
        id: 'sun-glasses',
        icon: gResourceRoot + 'fx/overlays/Sunglasses-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Sunglasses.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.0, y: 0.03},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.8}
      },
      {
        name: getLocalizedString('Monocle'),
        id: 'monocle',
        icon: gResourceRoot + 'fx/overlays/Monacle-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Monacle.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.LEFT_EYE,
                   offset: {x: -0.01, y: 0.3},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.8}
      },
      {
        name: getLocalizedString('Eye_Patch'),
        id: 'eye-patch',
        icon: gResourceRoot + 'fx/overlays/Eyepatch-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Eyepatch.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.0, y: -0.08},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.70}
      },
      {
        name: getLocalizedString('Scuba_Mask'),
        id: 'scuba-mask',
        icon: gResourceRoot + 'fx/overlays/ScubaMask-icon.png',
        resource: gOverlayRoot + 'fx/overlays/ScubaMask.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.06, y: 0.1},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.75}
      },
      {
        name: getLocalizedString('Thick_Rimmed'),
        id: 'thick-rimmed',
        icon: gResourceRoot + 'fx/overlays/glasses-icon.png',
        resource: gOverlayRoot + 'fx/overlays/glasses.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_ROOT,
                   offset: {x: 0.0, y: 0.05},
                   scaleWithFace: true,
                   rotateWithFace: true,
                   scale: 0.4}
      }
    ]
  },
  {
    id: 'facial-hair',
    title: getLocalizedString('Facial_Hair'),
    overlays: [
      {
        name: getLocalizedString('Beard'),
        id: 'beard',
        icon: gResourceRoot + 'fx/overlays/Beard-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Beard.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.2},
                   scale: 0.75,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Goatee'),
        id: 'goatee',
        icon: gResourceRoot + 'fx/overlays/Goatee-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Goatee.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.LOWER_LIP,
                   offset: {x: 0.0, y: .20},
                   scale: 0.8,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Handlebar_Mustache'),
        id: 'handlebar-moustache',
        icon: gResourceRoot + 'fx/overlays/Moustache_Handlebars-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Moustache_Handlebars.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.30},
                   scale: 0.75,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Bushy_Mustache'),
        id: 'bushy-moustache',
        icon: gResourceRoot + 'fx/overlays/Moustache_bushy-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Moustache_bushy.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.30},
                   scale: 0.75,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Thin_Mustache'),
        id: 'stache1',
        icon: gResourceRoot + 'fx/overlays/stache1-icon.png',
        resource: gOverlayRoot + 'fx/overlays/stache1.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.25},
                   scale: 0.6,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Handlebar_Mustache'),
        id: 'stache2',
        icon: gResourceRoot + 'fx/overlays/stache2-icon.png',
        resource: gOverlayRoot + 'fx/overlays/stache2.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.25},
                   scale: 0.6,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Weird_Mustache'),
        id: 'stache3',
        icon: gResourceRoot + 'fx/overlays/stache3-icon.png',
        resource: gOverlayRoot + 'fx/overlays/stache3.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.25},
                   scale: 0.6,
                   scaleWithFace: true,
                   rotateWithFace: true}
      },
      {
        name: getLocalizedString('Dapper_Mustache'),
        id: 'stache4',
        icon: gResourceRoot + 'fx/overlays/stache4-icon.png',
        resource: gOverlayRoot + 'fx/overlays/stache4.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.25},
                   scale: 0.6,
                   scaleWithFace: true,
                   rotateWithFace: true}
      }
    ]
  },
  {
    title: getLocalizedString('Props'),
    overlays: [
      {
        name: getLocalizedString('Birthday_Cake'),
        id: 'birthday-cake',
        icon: gResourceRoot + 'fx/overlays/Birthday_cake-icon.png',
        resource: gOverlayRoot + 'fx/overlays/Birthday_cake.png',
        options:  {trackingFeature:
                   gapi.hangout.av.effects.FaceTrackingFeature.NOSE_TIP,
                   offset: {x: 0.0, y: 0.45},
                   scale: 0.25,
                   scaleWithFace: false,
                   rotateWithFace: false}
      }
    ]
  }    
];

  // create a flat list of tracking overlays by iterating over our overlay data 
  // structure
  for (var i = 0; i < gOverlayData.length; i++)
  {
    gCurrentOverlays[i] = "none";
    var overlays = gOverlayData[i].overlays;
    for (var j  = 0; j < overlays.length; j++)
    {
      var overlay = overlays[j];
      var image = gapi.hangout.av.effects.createImageResource(overlay.resource);
      gOverlays[overlay.id] = image.createFaceTrackingOverlay(overlay.options);
      gOverlayToCategoryMap[overlay.id] = i;
    }
  }
}


/**
 * Function that selects an overlay by id.  It displays the overlay,
 * hides any overlay in the same category that was previously 
 * shown, and updates the UI.
 * @param {string} name The name (id) of the overlay
 */
function selectOverlay(name)
{
  var cat = gOverlayToCategoryMap[name];
  var overlays = gOverlayData[cat].overlays;
  for (var j in overlays) {
    var overlay = overlays[j];
    if(name !== overlay.id) {
      $('#' + overlay.id + '-button').googButton('toggleOff');
      hideOverlay(overlay.id);
    }
  }

  // handle special case for 'special' category -- we want it to be mutually
  // exclusive to all other effects
  if(gOverlayData[0].id == 'special') {
    if(cat == 0) {
      for(var i = 1; i < gOverlayData.length; i++) {
        for (var j in gOverlayData[i].overlays) {
          var overlay = gOverlayData[i].overlays[j];
          $('#' + overlay.id + '-button').googButton('toggleOff');
          hideOverlay(overlay.id);
        }
        gCurrentOverlays[i] = "none";
      }    
    }
     else {
      for (var j in gOverlayData[0].overlays) {
        var overlay = gOverlayData[0].overlays[j];
        $('#' + overlay.id + '-button').googButton('toggleOff');
        hideOverlay(overlay.id);
      }    
      gCurrentOverlays[0] = "none";
    }
  }

  if(gCurrentOverlays[cat] !== name) {
    gCurrentOverlays[cat] = name;
    showOverlay(name);
  } else {
    gCurrentOverlays[cat] = "none";
    hideOverlay(name);
  }
}



/**
 * Helper function that hides all overlays and updates UI.
 */
function hideAllOverlays()
{
  for (var index in gOverlays) {
    gOverlays[index].setVisible(false);
    $('#' + index + '-button').googButton('toggleOff');
  }
  for (var i = 0; i < gCurrentOverlays.length; i++)
    gCurrentOverlays[i] = "none";
}

/**
 * Helper function that hides a particular overlay
 * @param {string} name The name (id) of the overlay
 */
function hideOverlay(name)
{
  if(gOverlays[name].isVisible()) {
    gOverlays[name].setVisible(false);
    var curTime = new Date();
    var timeShownMs = curTime - gOverlayTimestamps[name];
    fireGAEvent("Effects", "Overlay_Data", name, timeShownMs);
  }
}

/**
 * Helper function that shows a particular overlay
 * @param {string} name The name (id) of the overlay
 */
function showOverlay(name)
{
  if(!gOverlays[name].isVisible()) {
    gOverlays[name].setVisible(true);
    gOverlayTimestamps[name] = new Date();
    fireGAEvent("Effects", "Show_Overlay_Hist", "" + gParticipants.length, 1);
    fireGAEvent("Effects", "Show_Overlay", name, gParticipants.length);
  }
}


/**
 * Creates the overlays and UI. Called as soon as the current
 * string localization file has been loaded.  
 */
function setupUI()
{
  createOverlays();
 
  var appContainer = $('#app-container'); 

  var titlebarDiv = $('#title-bar');

  var closeButton = $('<div />')
    .html('<a class="close-button"><img src="' 
      + gResourceRoot + 'fx/css/close-icon.png" '
      + 'alt="' + getLocalizedString('Close') + '" '
	  + 'title="' + getLocalizedString('Close') + '"></a>')
    .css({'float': 'right'})
    .click(function() {
      gapi.hangout.hideApp();
      fireGAEvent("Effects", "Hide_App");
      return false;
    });

  titlebarDiv.html(getLocalizedString("Effects"));
  titlebarDiv.append(closeButton);

  var bottomButtonBarDiv = $('#bottom-button-bar');

  var buttonDiv = $('<div />')
    .addClass('kd-buttonbar');

  var removeButton =  $('<a />')
    .googButton({darkbg:true, mini:true})
    .html(getLocalizedString('Remove_all'));
  removeButton.click(function() {
    hideAllOverlays();
    fireGAEvent("Effects", "Remove_All");
    return false;
  });

  buttonDiv.append(removeButton);
  bottomButtonBarDiv.append(buttonDiv);

  var overlayDiv = $('#effects-list');

  overlayDiv.css({"padding-top": "20px"});

  overlayDiv.height(appContainer.height() - 120);

  $(window).resize(function() {
  	overlayDiv.height(appContainer.height() - 120);
  });

  // build the overlay list from our global overlay data structure
  var firstCat = true;
  for (var i in gOverlayData) {
        
    // create the label & button bar for this category
    var categoryLabelDiv = $('<div />')
      .html(gOverlayData[i].title);
//      .css({'border-bottom': '1px solid #7c7c7c', 'padding-bottom': '5px'});
    if(!firstCat) categoryLabelDiv.css({'padding-top': '15px'});
    firstCat = false;

    overlayDiv.append(categoryLabelDiv);

    // loop through the overlays in this category, create buttons and add them
    // to the button bar we just created
    var overlays = gOverlayData[i].overlays;
    var count = 0;
    var categoryDiv;
    for (var j in overlays) {
      if(count % 5 == 0) {
        if(count != 0) overlayDiv.append(categoryDiv);
        categoryDiv = $('<div />')
          .addClass('kd-buttonbar')
          .css({'padding-top': '5px'});
        if(count != 0) categoryDiv.css({'padding-top': '10px'});
      }
      count++;

      var overlay = overlays[j];
      var button = $('<a />')
        .attr({id:overlay.id + '-button'})
        .googButton({small:true, toggle:true, darkbg:true})
        .html('<img src="' + overlay.icon + '" alt="'
          + overlay.name
          + '" title="' + overlay.name + '">');
      button.click(function(id) {
          return function () {
          selectOverlay(id);
          return false;
        }
      }(overlay.id));

      categoryDiv.append(button);
    }

    // add the label and the button bar to the list
    overlayDiv.append(categoryDiv);
  }


  var spacerDiv = $('<div />')
    .css({'height': '20px'});

  overlayDiv.append(spacerDiv);

  appContainer.googFocusContainer({'selector':'.kd-button,.close-button'});
  
  // Send ack to begin testing.
  sendAck();
}


/**
 * Called on page load.  Gets the current locale, loads
 * the appropriate string file (and causes the UI to get
 * setup when that successfully loads).
 */
function init()
{
  gapi.hangout.onApiReady.add(function(eventObj) {
    if(eventObj.isApiReady) {

      // keep track of the participants in the hangout
      // so we can report on the number of participants
      // when an effect is turned on
      gParticipants = gapi.hangout.getParticipants();
      gapi.hangout.onParticipantsChanged.add(function(event) {
        gParticipants = event.participants;
      });

      // fire an event to say the app is starting up
      fireGAEvent("Effects", "App_Starting");

      // get the locale
      var locale = gapi.hangout.getLocale();

      // load the localized strings and then build the UI
      $.getScript(gResourceRoot + 'fx/src/locale/' + locale + '/strings.js', 
        setupUI);
    }
  });
}

gadgets.util.registerOnLoadHandler(init);
